/**  
 * Copyright (c) IAct Inc. 2000-2009, All rights reserved.
 * @author Andy 
 * File: Tools.java
 * Created: 2012-7-26
 */
package com.iact.util;

import java.awt.Canvas;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.image.AreaAveragingScaleFilter;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.iact.ErrorCode;
import com.iact.IActException;
import com.iact.ResultFile;
import com.iact.vo.Bizpackageitem;
import com.jhlabs.image.ScaleFilter;

public class Tools {
	protected static final Log log = LogFactory.getLog(Tools.class);
	/**
	 * User order id
	 * 
	 * Lock is for controlling multi-thread synchronization, useed is
	 * base-number, we could think it is always different within one day.
	 * 
	 * System.currentTimeMillis / 1000 is current second
	 * 
	 * System.currentTimeMillis() / 1000) % 1000000 is last six number
	 * 
	 */
	private static byte[] ULOCK = new byte[0];
	private static int useed = (int) ((System.currentTimeMillis() / 1000) % 1000000);

	/**
	 * Return a unique <code>ID</code>
	 * 
	 * @return <code>ID</code>
	 */
	public static String getOrderID() {
		String trans = null;
		synchronized (ULOCK) {
			useed = useed + 1;
			if (useed / 100000 > 0) {
				trans = Integer.toString(useed);
			} else if (useed / 10000 > 0) {
				trans = "0" + useed;
			} else if (useed / 1000 > 0) {
				trans = "00" + useed;
			} else if (useed / 100 > 0) {
				trans = "000" + useed;
			} else if (useed / 10 > 0) {
				trans = "0000" + useed;
			} else {
				trans = "00000" + useed;
			}
		}

		Calendar now = Calendar.getInstance();
		String dt = Integer.toString(now.get(Calendar.YEAR))
				+ Integer.toString(now.get(Calendar.MONTH) + 1)
				+ Integer.toString(now.get(Calendar.DATE));
		return dt + trans;
	}

	/**
	 * Transaction id
	 * 
	 */
	private static byte[] TLOCK = new byte[0];
	private static int tseed = (int) ((System.currentTimeMillis() / 1000) % 1000000);

	/**
	 * Return a unique <code>ID</code>
	 * 
	 * @return <code>ID</code>
	 */
	public static String getTransID() {
		String trans = null;
		synchronized (TLOCK) {
			tseed = tseed + 1;
			if (tseed / 100000 > 0) {
				trans = Integer.toString(tseed);
			} else if (tseed / 10000 > 0) {
				trans = "0" + tseed;
			} else if (tseed / 1000 > 0) {
				trans = "00" + tseed;
			} else if (tseed / 100 > 0) {
				trans = "000" + tseed;
			} else if (tseed / 10 > 0) {
				trans = "0000" + tseed;
			} else {
				trans = "00000" + tseed;
			}
		}
		Calendar now = Calendar.getInstance();
		String dt = Integer.toString(now.get(Calendar.YEAR))
				+ Integer.toString(now.get(Calendar.MONTH) + 1)
				+ Integer.toString(now.get(Calendar.DATE));
		return dt + trans;
	}

	/**
	 * User pay one order id generated by web site.
	 * 
	 * Lock is for controlling multi-thread synchronization, pseed is
	 * base-number, we could think it is always different within one day.
	 * 
	 * System.currentTimeMillis / 1000 is current second
	 * 
	 * System.currentTimeMillis() / 1000) % 1000000 is last six number
	 * 
	 */
	private static byte[] PLOCK = new byte[0];
	private static int pseed = (int) ((System.currentTimeMillis() / 1000) % 1000000);

	/**
	 * Return a unique <code>ID</code>
	 * 
	 * @return <code>ID</code>
	 */
	public static String getPayonlineID() {
		String trans = null;
		synchronized (PLOCK) {
			pseed = pseed + 1;
			if (pseed / 100000 > 0) {
				trans = Integer.toString(pseed);
			} else if (pseed / 10000 > 0) {
				trans = "0" + pseed;
			} else if (useed / 1000 > 0) {
				trans = "00" + pseed;
			} else if (useed / 100 > 0) {
				trans = "000" + pseed;
			} else if (useed / 10 > 0) {
				trans = "0000" + pseed;
			} else {
				trans = "00000" + pseed;
			}
		}

		Calendar now = Calendar.getInstance();
		String dt = Integer.toString(now.get(Calendar.YEAR))
				+ Integer.toString(now.get(Calendar.MONTH) + 1)
				+ Integer.toString(now.get(Calendar.DATE));
		return dt + trans;
	}

	private static final String ACTION = "alipay.do";
	private static final String METHOD = "post";
	private static final String BUTTON = "确定";

	public static String buildSBForm(Map<String, String> paramMap) {
		StringBuffer sbHtml = new StringBuffer();

		sbHtml
				.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\""
						+ ACTION + "\" method=\"" + METHOD + "\">");
		for (String key : paramMap.keySet()) {

			String value = (String) paramMap.get(key);
			sbHtml.append("<input type=\"hidden\" name=\"" + key
					+ "\" value=\"" + value + "\"/>");
		}

		sbHtml.append("<input type=\"submit\" value=\"" + BUTTON
				+ "\" style=\"display:none;\"></form>");
		sbHtml
				.append("<script>document.forms['alipaysubmit'].submit();</script>");

		return sbHtml.toString();
	}

	/**
	 * Return random file name base on current session and current time.
	 * 
	 * @param sessionid
	 * @return
	 */
	public static String getRDFileAbsolutePath(String basePath,
			String sessionid, String suffix) {
		int second = (int) ((System.currentTimeMillis() / 1000) % 1000000);
		String fileName = sessionid + second;

		String realPath = basePath;
		if (realPath.endsWith("/")) {
			return realPath + "images/temp/" + fileName + "." + suffix;
		} else {
			return realPath + "/images/temp/" + fileName + "." + suffix;
		}

	}

	/**
	 * The max size of upload resource image
	 */
	private static final long MAX_SIZE;

	/**
	 * File type of allowed upload
	 */
	private static final String[] ALLOWED_EXT;

	/**
	 * need to scale image size or not
	 */
	private static final boolean SCALE_IMAGE_SIZE;

	private static final String[] IMAGE_SCALES = new String[] { "120*80",
			"160*120" };

	static {
		Properties config = new Properties();
		InputStream ins = Tools.class.getClassLoader().getResourceAsStream(
				"config.properties");
		try {
			config.load(ins);
		} catch (IOException e) {
			log.error(e);
		}
		MAX_SIZE = Integer.parseInt(config.getProperty("MAX_SIZE")) * 1024;

		String ext = config.getProperty("ALLOWED_IMAGE", "png");
		ALLOWED_EXT = ext.split(",");

		SCALE_IMAGE_SIZE = Boolean.parseBoolean(config.getProperty(
				"SCALE_IMAGE_SIZE", "false"));

	}

	public static ResultFile uploadLogo(HttpServletRequest req)
			throws IActException {

		FileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload fileload = new ServletFileUpload(factory);
		String fileRes = null;
		//fileload.setSizeMax(MAX_SIZE);

		String imageScaleStr = req.getParameter("imageScale");
		int imageW = 120;
		int imageH = 80;
		if (imageScaleStr != null && imageScaleStr.equalsIgnoreCase("1")) {
			imageW = 160;
			imageH = 120;
		}
		try {
			List<FileItem> files = fileload.parseRequest(req);
			if (files != null) {
				for (FileItem item : files) {
					if (item.isFormField()) {
						continue;
					}

					if (item.getSize() > MAX_SIZE) {
						return new ResultFile(ErrorCode.LARGER_THAN_MAX_UPSIZE,
								"上传文件超过" + MAX_SIZE / 1024 + "K");
					}
					String fileName = item.getName();
					String ext = null;
					if (fileName != null) {
						ext = getFileSuffix(fileName);
						boolean allowed = allowedImage(ext);
						if (!allowed) {
							return new ResultFile(ErrorCode.ILLEGAL_FILE_TYPE,
									"上传文件类型" + ext + "不对");
						}
					}
					byte[] logo = item.get();

					String sessionId = req.getSession().getId();
					String basePath = req.getSession().getServletContext()
							.getRealPath("/");

					fileRes = getRDFileAbsolutePath(basePath, sessionId, ext);
					File f = new File(fileRes);
					if (f.exists()) {
						f.delete();
					}
					f = new File(fileRes);
					try {
						f.createNewFile();
					} catch (IOException e1) {
						throw new IActException(e1);
					}

					if (SCALE_IMAGE_SIZE) {
						boolean succeed = scaleImage(logo, imageW, imageH,
								fileRes);
						if (!succeed) {
							return new ResultFile(ErrorCode.ERROR,
									"缩放不符合规格图片出错");
						}
					} else {
						FileOutputStream out = null;
						try {
							out = new FileOutputStream(f);
							out.write(logo);
						} catch (IOException e) {
							throw new IActException(e);
						} finally {
							if (out != null) {
								try {
									out.flush();
									out.close();
								} catch (IOException e) {
									throw new IActException(e);
								}
							}
						}
					}
					return new ResultFile(fileRes.substring(fileRes
							.lastIndexOf("/") + 1));
				}
			}
		} catch (FileUploadException e) {
			throw new IActException(e);
		}
		return new ResultFile(ErrorCode.ERROR, "未知错误");

	}

	public static boolean allowedImage(String fileExt) {
		for (int i = 0; i < ALLOWED_EXT.length; i++) {
			if (fileExt.equalsIgnoreCase(ALLOWED_EXT[i])) {
				return true;
			}
		}
		return false;
	}

	public static String getFileSuffix(String fileName) {
		int pos = fileName.lastIndexOf(".") + 1;
		String ext = fileName.substring(pos);
		return ext;
	}

	/**
	 * Write a image to file
	 * 
	 * @param buffImage
	 * @param fileName
	 * @throws IOException
	 */
	public static void writeImageToFile(BufferedImage buffImage, String fileName)
			throws IActException {

		String ext;
		Iterator imageWriters;
		ImageOutputStream ios;
		ImageWriter imageWriter = null;

		ext = fileName.substring(fileName.lastIndexOf('.') + 1);
		imageWriters = ImageIO.getImageWritersBySuffix(ext);

		try {
			ios = ImageIO.createImageOutputStream(new File(fileName));

			if (imageWriters.hasNext()) {
				imageWriter = (ImageWriter) imageWriters.next();
			}
			imageWriter.setOutput(ios);
			imageWriter.write(buffImage);
			ios.close();
		} catch (IOException e) {
			throw new IActException(e);
		}

	}

	/**
	 * Read byte array to buffered image
	 * 
	 * @param bs
	 * @throws IActException
	 */
	public static BufferedImage readImageFromByte(byte[] bs)
			throws IActException {

		BufferedImage ret = null;
		try {
			ret = ImageIO.read(new ByteArrayInputStream(bs));
		} catch (IOException e) {
			throw new IActException(e);
		}

		return ret;

	}

	/**
	 * Scale image to specified width, height and color mode.
	 * 
	 * @param src
	 * @param distW
	 * @param distH
	 * @param imageType
	 * @return
	 */
	public static BufferedImage filterImage(BufferedImage src, int distW,
			int distH) {
		BufferedImage dist = new BufferedImage(distW, distH,
				BufferedImage.TYPE_3BYTE_BGR);

		ScaleFilter scale = new ScaleFilter(distW, distH);
		scale.filter(src, dist);

		return dist;

	}

	private static Component component = new Canvas();

	public static BufferedImage filterImageByAVG(BufferedImage image,
			int width, int height) {

		AreaAveragingScaleFilter areaAveragingScaleFilter = new AreaAveragingScaleFilter(
				width, height);
		FilteredImageSource filteredImageSource = new FilteredImageSource(image
				.getSource(), areaAveragingScaleFilter);
		BufferedImage bufferedImage = new BufferedImage(width, height,
				BufferedImage.TYPE_3BYTE_BGR);
		Graphics graphics = bufferedImage.createGraphics();
		graphics.drawImage(component.createImage(filteredImageSource), 0, 0,
				null);

		return bufferedImage;
	}

	public static boolean scaleImage(byte[] bs, int width, int height,
			String fileName) throws IActException {
		BufferedImage src = readImageFromByte(bs);
		int w = src.getWidth();
		int h = src.getHeight();
		boolean matched = matchedScale(w, h);
		if (matched) {
			return true;
		}
		// BufferedImage dist = filterImage(src, width, height);
		BufferedImage dist = filterImageByAVG(src, width, height);
		writeImageToFile(dist, fileName);

		return true;

	}

	public static boolean matchedScale(int w, int h) {
		String scale = Integer.toString(w) + "*" + Integer.toString(h);
		for (int i = 0, len = IMAGE_SCALES.length; i < len; i++) {
			if (scale.equalsIgnoreCase(IMAGE_SCALES[i])) {
				return true;
			}
		}
		return false;
	}

	public static String getLatest30Days() {
		Date date = new Date();
		int year = Integer.parseInt(new SimpleDateFormat("yyyy").format(date));
		int month = Integer.parseInt(new SimpleDateFormat("MM").format(date)) - 1;
		int day = Integer.parseInt(new SimpleDateFormat("dd").format(date));

		if (month == 0) {
			year -= 1;
			month = 12;
		} else if (day > 28) {
			if (month == 2) {
				if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
					day = 29;
				} else
					day = 28;
			} else if ((month == 4 || month == 6 || month == 9 || month == 11)
					&& day == 31) {
				day = 30;
			}
		}
		String y = year + "";
		String m = "";
		String d = "";
		if (month < 10)
			m = "0" + month;
		else
			m = month + "";
		if (day < 10)
			d = "0" + day;
		else
			d = day + "";

		return y + "-" + m + "-" + d + " 00:00:00";
	}
	
	public static List<Bizpackageitem> sortPackageItems(Set<Bizpackageitem> items) {
		if (items == null) {
			return null;
		}
		List<Bizpackageitem> list = new ArrayList<Bizpackageitem>();
		for (Bizpackageitem item: items) {
			list.add(item);
		}
		Collections.sort(list);
		return list;
		
	}
	
	public static String getMobileAuthCode() {
		Random r = new Random();
		int base = r.nextInt(10000);		
		
		int res = 0;
		if (base < 10) {
			res = base * 1000;
		} else if (base < 100) {
			res = base * 100;
		} else if (base < 1000) {
			res = base * 10;
		} else {
			res = base;
		}
		return Integer.toString(res);
		
	}
	
	public static String getRandomPWD() {
		Random r = new Random();
		int base = r.nextInt(1000000);		
		
		int res = 0;
		if (base < 10) {
			res = base * 100000;
		} else if (base < 100) {
			res = base * 10000;
		} else if (base < 1000) {
			res = base * 1000;
		} else if (base < 10000) {
			res = base * 100;
		} else if (base < 100000) {
			res = base * 10;
		} else {
			res = base;
		}
		return Integer.toString(res);
		
	}

}
